﻿// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

namespace SketchFlow.SaveState.Interactions
{
	using System.Collections.Generic;
	using System.Linq;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Media;
	using Microsoft.Expression.Prototyping.Services;

	internal static class DependencyObjectHelper
	{
		public const string PathFormatString = "{0}/{1}";

		public static IEnumerable<DependencyObject> GetVisualChildren(DependencyObject parent)
		{
			int count = VisualTreeHelper.GetChildrenCount(parent);
			for (int index = 0; index < count; index++)
			{
				yield return VisualTreeHelper.GetChild(parent, index);
			}
		}

		public static IEnumerable<DependencyObject> GetSelfAndVisualAncestors(DependencyObject child)
		{
			for ( ; child != null; child = VisualTreeHelper.GetParent(child))
			{
				yield return child;
			}
		}

		public static string GeneratePathString(DependencyObject element, string keyPrefix, string keySuffix)
		{
			// get a listing of the types from SketchFlow Player's model
			List<string> screenTypeNames = (
				from screen in PlayerContext.Instance.RuntimeData.Screens
				select screen.ClassName)
				.ToList();

			// find the topmost SketchFlow screen
			DependencyObject topmostScreen = (
				from ancestor in DependencyObjectHelper.GetSelfAndVisualAncestors(element)
				let typeName = ancestor.GetType().FullName
				where screenTypeNames.Contains(typeName)
				select ancestor)
				.LastOrDefault();
			if (topmostScreen == null)
			{
				return null;
			}

			// get the visual ancestors up to but not including the topmost screen
			List<DependencyObject> visualHierarchy = DependencyObjectHelper.GetSelfAndVisualAncestors(element)
				.TakeWhile(visual => visual != topmostScreen)
				.ToList();

			// walk up to it, recording child indices at each level in the visual tree
			IEnumerable<int> indices = (
				from child in visualHierarchy
				let parent = VisualTreeHelper.GetParent(child)
				let siblings = DependencyObjectHelper.GetVisualChildren(parent).ToList()
				let index = siblings.IndexOf(child)
				select index)
				.Reverse();

			// create the path to the screen
			string key = string.Format(PathFormatString, keyPrefix, topmostScreen.GetType().FullName);
			foreach (int index in indices)
			{
				key = string.Format(PathFormatString, key, index);
			}

			// add the group name
			key = string.Format(PathFormatString, key, keySuffix);

			return key;
		}
	}
}
